package com.zhugeio.common;


import java.util.*;
import java.util.stream.Stream;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * Redis 客户端集群版
 *
 * @author 张泽立
 * 2019-1-8
 */
public class RedisClient{

    private static  JedisPool jedisPool;

    static {
        JedisPoolConfig config = new JedisPoolConfig();
        // 控制一个pool可分配多少个jedis实例，通过pool.getResource()来获取；
        // 如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
        config.setMaxTotal(500);
        // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
        config.setMaxIdle(20);
        config.setMinIdle(5);
        // 表示当borrow(引入)一个jedis实例时，最大的等待时间，如果超过等待时间，则直接抛出JedisConnectionException；
        config.setMaxWaitMillis(60000);
        config.setTimeBetweenEvictionRunsMillis(3000);// #多长时间检查一次连接池中空闲的连接
        config.setMinEvictableIdleTimeMillis(2000);// #空闲连接多长时间后会被收回
        // 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
        config.setTestOnBorrow(true);

        jedisPool = new JedisPool("redis://:123456@192.168.137.12:6379");
//        jedisPool = new JedisPool("redis://:"+Global.REDIS_SERVER_PASSWORD+"@"+Global.REDIS_SERVER_URL+":"+Global.REDIS_SERVER_PORT);
//        jedisPool = new JedisPool(config, Global.REDIS_SERVER_URL,  Integer.parseInt(Global.REDIS_SERVER_PORT), "zjp_Redis_224");
//		jedisPool = new JedisPool(config,"54.222.236.168",6379);
//		jedisPool = new JedisPool(config,ArgsUtil.getArgs(Contants.SSDB_IP),Integer.valueOf(ArgsUtil.getArgs(Contants.SSDB_PORT)));

    }


    public static  String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.set(key, value);
        jedis.close();
        return result;
    }
    public static  String set(String key, String value, Long expireSecond) {
        Jedis jedis = jedisPool.getResource();
        boolean keyExist = jedis.exists(key);
        // NX是不存在时才set， XX是存在时才set， EX是秒，PX是毫秒
        if (keyExist) {
            jedis.del(key);
        }
        String result = jedis.set(key, value, "NX", "EX", expireSecond);
        jedis.close();
        return result;
    }

    public static  String get(String key) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.get(key);
        jedis.close();
        return result;
    }

    public static Long hset(String key, String item, String value,int seconds) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hset(key, item, value);
        jedis.expire(key,seconds);
        jedis.close();
        return result;
    }

    public static  String hget(String key, String item) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.hget(key, item);
        jedis.close();
        return result;
    }

    /**
     * Redis Hmget 命令用于返回哈希表中，一个或多个给定字段的值。
     如果指定的字段不存在于哈希表，那么返回一个 nil 值。
     * @param key
     * @param item
     * @return 一个包含多个给定字段关联值的表，表值的排列顺序和指定字段的请求顺序一样。
     */
    public static  List<String> hmget(String key, String... item) {
        Jedis jedis = jedisPool.getResource();
        List<String> result = jedis.hmget(key, item);
        jedis.close();
        return result;
    }

    public static  Long incr(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.incr(key);
        jedis.close();
        return result;
    }

    public static  Long decr(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.decr(key);
        jedis.close();
        return result;
    }

    public static Long expire(String key, int second) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.expire(key, second);
        jedis.close();
        return result;
    }

    public static Long ttl(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.ttl(key);
        jedis.close();
        return result;
    }

    public static Long hdel(String key, String item) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.hdel(key, item);
        jedis.close();
        return result;
    }

    public static Long del(String key) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.del(key);
        jedis.close();
        return result;
    }

    public static Long rpush(String key, String... strings) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.rpush(key, strings);
        jedis.close();
        return result;
    }

    /**
     * Redis Lrange 返回列表中指定区间内的元素，区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素， 1 表示列表的第二个元素，以此类推。
     * 你也可以使用负数下标，以 -1 表示列表的最后一个元素， -2 表示列表的倒数第二个元素，以此类推。
     * @param key
     * @param start
     * @param end
     * @return
     */
    public static List<String> lrange(String key, int start, int end) {
        Jedis jedis = jedisPool.getResource();
        List<String> result = jedis.lrange(key, start, end);
        jedis.close();
        return result;
    }

    /**
     * 从列表中从头部开始移除count个匹配的值。如果count为零，所有匹配的元素都被删除。如果count是负数，内容从尾部开始删除。
     * @param key
     * @param count
     * @param value
     */
    public static Long lrem(String key, Long count, String value) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.lrem(key, count, value);
        jedis.close();
        return result;
    }

    /**
     * Redis Zadd 命令用于将一个或多个成员元素及其分数值加入到有序集当中。
     如果某个成员已经是有序集的成员，那么更新这个成员的分数值，并通过重新插入这个成员元素，来保证该成员在正确的位置上。
     分数值可以是整数值或双精度浮点数。
     如果有序集合 key 不存在，则创建一个空的有序集并执行 ZADD 操作。
     当 key 存在但不是有序集类型时，返回一个错误。
     * @param key
     * @param score
     * @param member
     * @return 被成功添加的新成员的数量，不包括那些被更新的、已经存在的成员。
     */
    public static Long zadd(String key, double score, String member,int seconds) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.zadd(key, score, member);
        jedis.expire(key,seconds);
        jedis.close();
        return result;
    }

    public static Long zrem(String key, String member) {
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.zrem(key, member);
        jedis.close();
        return result;
    }

    /**
     * Redis Zrevrangebyscore 返回有序集中指定分数区间内的所有的成员。有序集成员按分数值递减(从大到小)的次序排列。
     具有相同分数值的成员按字典序的逆序(reverse lexicographical order )排列。
     除了成员按分数值递减的次序排列这一点外， ZREVRANGEBYSCORE 命令的其他方面和 ZRANGEBYSCORE 命令一样。
     * @param key
     * @param max
     * @param min
     * @param offset
     * @param count
     * @return 指定区间内，带有分数值(可选)的有序集成员的列表。
     */
    public static Set<String> zrevrangebyscore(String key, String max, String min, int offset, int count){
        Jedis jedis = jedisPool.getResource();
        Set<String> result = jedis.zrevrangeByScore(key, max, min, offset, count);
        jedis.close();
        return result;
    }

    public static Long zcrad(String key){
        Jedis jedis = jedisPool.getResource();
        Long result = jedis.zcard(key);
        jedis.close();
        return result;
    }



    public  static Map<String,Object> queryMemberResentGoods( int page, int pageSize) {
        Jedis jedis = jedisPool.getResource();
        String key = "app_history";
        //获取用户的浏览的商品的总页数;
        long pageCounts = jedis.ttl(key);
        long pageCount = jedis.llen(key);

        System.out.println(pageCount);
        //根据用户的ID分頁获取该用户最近浏览的50个商品信息
        List<String> result = jedis.lrange(key,(page-1)*pageSize,page*pageSize-1);
        //拼装返回
        Map<String,Object> map = new HashMap<>();
        map.put("result",result);
        map.put("pageCount",(pageCount%pageSize == 0 ? pageCount/pageSize : pageCount/pageSize+1));
        jedis.close();
        return map;
    }


    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "EX";

    /**
     * 尝试获取分布式锁
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock( String lockKey, String requestId, int expireTime) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
        jedis.close();
        if (LOCK_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

    private static final Long RELEASE_SUCCESS = 1L;

    /**
     * 释放分布式锁
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(String lockKey, String requestId) {
        Jedis jedis = jedisPool.getResource();
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
        jedis.close();
        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }

}

